<?php

namespace App\Services\Scenic\Tuniu;

use App\Jobs\Scenic\SyncScenicDetail;
use App\Models\Scenic\ScenicOrder;
use App\Services\Http;
use App\Trip\Enums\Scenic\ScenicProvider;
use Illuminate\Support\Facades\Cache;

class TuniuService
{
    const SCENIC_LIST_URI = '/Ticket/scenicList';
    const SCENIC_DETAIL_URI = '/Ticket/scenicDetail';
    const SCENIC_TICKET_DETAIL_URI = '/Ticket/detail';

    const SCENIC_TICKET_CREATE_ORDER_URI = '/Ticket/createOrderNew';
    const SCENIC_TICKET_CANCEL_ORDER_URI = '/Ticket/cancelOrder';
    const SCENIC_TICKET_SUBMIT_ORDER_URI = '/Ticket/submitOrder';
    const SCENIC_TICKET_ORDER_DETAIL_URI = '/Ticket/orderDetail';
    const SCENIC_TICKET_ORDER_STATUS_URI = '/Ticket/orderStatus';
    const SCENIC_TICKET_TUIPIAO_URI = '/Ticket/tuiPiao';

    protected string $apiUrl;
    protected string $apikey;
    protected string $acctId;
    protected string $secretkey;
    protected string $payType;

    public function __construct()
    {
        $this->apiUrl = config('trip.scenic.tuniu.apiurl');
        $this->secretkey = config("trip.scenic.tuniu.secretkey");
        $this->apikey = config("trip.scenic.tuniu.apikey");
        $this->acctId = config("trip.scenic.tuniu.acctId");
        $this->payType = config("trip.scenic.tuniu.payType");
    }

    /**
     * 设置签名
     * @param $params
     * @return string
     */
    public function makeSign($params): string
    {
        $tmpArr = [];
        $tmpArr[] = $this->secretkey;
        ksort($params);
        foreach ($params as $key => $value) {
            if ($key == 'sign' || empty($value)) {
                continue;
            }
            if (is_array($value) || is_object($value)) {
                $value = json_encode($value);
            }
            $tmpArr[] = sprintf('%s=%s', $key, $value);
        }
        $tmpArr[] = $this->secretkey;
        $str = implode('&', $tmpArr);

        return strtoupper(md5($str));
    }

    /**
     * 组合参数
     * @param $params
     * @return array
     */
    public function buildParams($params): array
    {
        $newParams = [
            'apiKey' => $this->apikey,
            'timestamp' => date('Y-m-d H:i:s')
        ];
        $signStr = $this->makeSign(array_merge($newParams,$params));
        $newParams['sign'] = $signStr;
        $newParams['data'] = $params;

        return $newParams;
    }

    /**
     * 查询景点
     * @param string $keyword
     * @param int $page
     * @param int $pageSize
     * @return mixed
     * @throws \Exception
     */
    public function searchScenic(string $keyword,int $page,int $pageSize):object
    {
        $cacheKey = "scenicService:tuNiu:searchScenic:".md5($keyword.$page.$pageSize);
        $res = Cache::get($cacheKey);
        if (!empty($res)) {
            $result = json_decode($res);
            return $result->data;
        }
        $data = [
            'pageSize'=>$pageSize,
            'page'=>$page,
            'key'=>$keyword
        ];
        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_LIST_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
           throw new \Exception($result->msg,$result->errorCode);
        }
        $cacheTime = config('trip.ttl.day') * 1;
        Cache::put($cacheKey, $res, $cacheTime);
        if (!empty($result->data->rows)){
            foreach ($result->data->rows as $row){
                SyncScenicDetail::dispatch($row->scenicId,ScenicProvider::TUNIU->value)->onQueue('{syncScenic}');
            }
        }
        return $result->data;
    }

    /**
     * 获取景点详情
     * @param string $scenicId
     * @return mixed
     * @throws \Exception
     */
    public function scenicDetail(string $scenicId):object
    {
        $cacheKey = "scenicService:tuNiu:scenicDetail:".$scenicId;
        $res = Cache::get($cacheKey);
        if (!empty($res)) {
            $result = json_decode($res);
            return $result->data;
        }
        $data = [
            'scenicId'=>$scenicId,
        ];
        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_DETAIL_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        $cacheTime = config('trip.ttl.day') * 1;
        Cache::put($cacheKey, $res, $cacheTime);
        return $result->data;
    }

    /**
     * 获取门票详情
     * @param string $productId
     * @return mixed
     * @throws \Exception
     */
    public function ticketDetail(string $productId):object
    {
        $cacheKey = "scenicService:tuNiu:ticketDetail:".$productId;
        $res = Cache::get($cacheKey);
        if (!empty($res)) {
            $result = json_decode($res);
            return $result->data;
        }
        $data = [
            'productId'=>$productId,
        ];
        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_DETAIL_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        $cacheTime = config('trip.ttl.day') * 1;
        Cache::put($cacheKey, $res, $cacheTime);
        return $result->data;
    }

    /**
     * 创建订单
     * @param string $sourceOrderId
     * @param string $productId
     * @param string $startTime
     * @param int $bookNumber
     * @param array $contact
     * @param array $touristList
     * @param array $delivery
     * @param int $couponValue
     * @return mixed
     * @throws \Exception
     */
    public function createOrder(string $sourceOrderId,string $productId,string $startTime,int $bookNumber,array $contact,array $touristList = [],array $delivery= [],int $couponValue = 0) :object
    {
        $data = [
            'sourceOrderId'=>$sourceOrderId,
            'acctId'=>$this->acctId,
            'productId'=>$productId,
            'startTime'=>$startTime,
            'bookNumber'=>$bookNumber,
            'contact'=>$contact,
        ];
        if ($touristList){
            $data['touristList'] = $touristList;
        }
        if ($delivery){
            $data['delivery'] = $delivery;
        }
        if ($couponValue){
            $data['couponValue'] = $couponValue;
        }

        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_CREATE_ORDER_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        return $result->data;
    }

    /**
     * 取消订单
     * @param string $orderId
     * @param string $remark
     * @return void
     */
    public function cancelOrder(string $orderId,string $remark):bool
    {
        $data = [
            'orderId'=>$orderId,
            'remark'=>$remark,
        ];

        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_CANCEL_ORDER_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        return true;
    }

    /**
     * 出票(代扣)
     * @param string $orderId
     * @param int $payAmount
     * @param string $platform
     * @return mixed
     * @throws \Exception
     */
    public function submitOrder(string $orderId,int $payAmount,string $platform = '10001') :object
    {
        $data = [
            'orderId'=>$orderId,
            'pay'=>$payAmount,
            'acctId'=>$this->acctId,
            'payType'=>$this->payType,
            'platform'=>$platform,
        ];

        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_SUBMIT_ORDER_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        return $result->data;
    }

    /**
     * 订单详情
     * @param string $orderId
     * @return mixed
     * @throws \Exception
     */
    public function orderDetail(string $orderId) :object
    {
        $data = [
            'orderId'=>$orderId,
            'acctId'=>$this->acctId,
        ];

        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_ORDER_DETAIL_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        return $result->data;
    }

    /**
     * @param string $orderId
     * @return mixed
     * @throws \Exception
     */
    public function orderStatus(string $orderId) :int
    {
        $data = [
            'orderId'=>$orderId,
            'acctId'=>$this->acctId,
        ];

        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_ORDER_STATUS_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            throw new \Exception($result->msg,$result->errorCode);
        }
        $statusMap = [
            '待确认'=>ScenicOrder::PROVIDER_ORDER_STATE_WAIT_SUBMIT,
            '待付款'=>ScenicOrder::PROVIDER_ORDER_STATE_WAIT_PAY,
            '出票中（已确认）'=>ScenicOrder::PROVIDER_ORDER_STATE_SUBMIT,
            '已完成'=>ScenicOrder::PROVIDER_ORDER_STATE_COMPLETE,
            '已取消'=>ScenicOrder::PROVIDER_ORDER_STATE_CANCEL,
        ];
        return $statusMap[$result->data->orderStatus] ?? ScenicOrder::PROVIDER_ORDER_STATE_UNKNOWN;
    }


    /**
     * 退票
     * @param string $orderId
     * @param int $causeType
     * @param string $causeContent
     * @return object
     * @throws \Exception
     */
    public function refundTicket(string $orderId,int $causeType,string $causeContent) :array
    {
        $data = [
            'orderId'=>$orderId,
            'causeType'=>$causeType,
            'causeContent'=>$causeContent,
        ];

        $params = $this->buildParams($data);
        $httpService = new Http();
        $httpService->setUrl($this->apiUrl.self::SCENIC_TICKET_TUIPIAO_URI);
        $httpService->setParam($params,true,true);
        $res = $httpService->postJson();
        $result = json_decode($res);
        if (!$result->success){
            return [
                'success'=>false,
                'msg'=>$result->msg,
            ];
        }
        return [
            'success'=>true,
            'msg'=>$result->data->msg,
        ];
    }

}
